/*******************************************************************************
*
*   FILE NAME:
*       Vector3.cpp - Vector3 class implementation
*
*   DESCRIPTION:
*       Defines a vector with three components.
*
*******************************************************************************/
#include "Vector3.h"

#include <math.h>
#include <string.h>

const Vector3 Backward;
const Vector3 Down = Vector3( 0.0f, -1.0f, 0.0f );
const Vector3 Forward;
const Vector3 Left = Vector3( -1.0f, 0.0f, 0.0f );
const Vector3 One = Vector3( 1.0f, 1.0f, .0f );
const Vector3 Right = Vector3( 1.0f, 0.0f, 0.0f );
const Vector3 UnitX = Vector3( 1.0f, 0.0f, 0.0f );
const Vector3 UnitY = Vector3( 0.0f, 1.0f, 0.0f );
const Vector3 UnitZ = Vector3( 0.0f, 0.0f, 1.0f );
const Vector3 Up = Vector3( 0.0f, 1.0f, 0.0f );
const Vector3 Zero = Vector3( 0.0f, 0.0f, 0.0f );

Vector3::Vector3( void )
    : X( 0.0f ),
      Y( 0.0f ),
      Z( 0.0f )
{
}

Vector3::Vector3( float32 value )
    : X( value ),
      Y( value ),
      Z( value )
{
}

Vector3::Vector3( float32 x, float32 y, float32 z )
    : X( x ),
      Y( y ),
      Z( z )
{
}

Vector3::Vector3( const Vector3& other )
    : X( other.X ),
      Y( other.Y ),
      Z( other.Z )
{
}

Vector3::~Vector3( void )
{
}

Vector3& Vector3::operator=( const Vector3& other )
{
    X = other.X;
    Y = other.Y;
    Z = other.Z;
    return *this;
}

boolean operator==( const Vector3& vec1, const Vector3& vec2 )
{
    return ( vec1.X == vec2.X && vec1.Y == vec2.Y && vec1.Z == vec2.Z );
}

boolean operator!=( const Vector3& vec1, const Vector3& vec2 )
{
    return ( vec1.X != vec2.X || vec1.Y != vec2.Y || vec1.Z != vec2.Z );
}

Vector3 operator+( const Vector3& vec1, const Vector3& vec2 )
{
    return Vector3::Add( vec1, vec2 );
}

Vector3 operator-( const Vector3& vec1, const Vector3& vec2 )
{
    return Vector3::Subtract( vec1, vec2 );
}

Vector3 operator*( const Vector3& vec1, const Vector3& vec2 )
{
    return Vector3::Multiply( vec1, vec2 );
}

Vector3 operator*( const Vector3& vec, float32 scalar )
{
    return Vector3::Multiply( vec, scalar );
}

Vector3 operator*( float32 scalar, const Vector3& vec )
{
    return Vector3::Multiply( vec, scalar );
}

Vector3 operator/( const Vector3& vec1, const Vector3& vec2 )
{
    return Vector3::Divide( vec1, vec2 );
}

Vector3 operator/( const Vector3& vec, float32 divider )
{
    return Vector3::Divide( vec, divider );
}

Vector3 operator-( const Vector3& vec )
{
    return Vector3::Negate( vec );
}

Vector3 Vector3::Add( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Add( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Clamp( const Vector3& vec, const Vector3& min, const Vector3& max )
{
    Vector3 ret;
    Clamp( vec, min, max, ret );
    return ret;
}

Vector3 Vector3::Cross( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Cross( vec1, vec2, ret );
    return ret;
}

float32 Vector3::Distance( const Vector3& vec1, const Vector3& vec2 )
{
    float32 ret;
    Distance( vec1, vec2, ret );
    return ret;
}

float32 Vector3::DistanceSquared( const Vector3& vec1, const Vector3& vec2 )
{
    float32 ret;
    DistanceSquared( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Divide( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Divide( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Divide( const Vector3& vec, float32 divider )
{
    Vector3 ret;
    Divide( vec, divider, ret );
    return ret;
}

float32 Vector3::Dot( const Vector3& vec1, const Vector3& vec2 )
{
    float32 ret;
    Dot( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Max( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Max( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Min( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Min( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Multiply( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Multiply( vec1, vec2, ret );
    return ret;
}

Vector3 Vector3::Multiply( const Vector3& vec, float32 scalar )
{
    Vector3 ret;
    Multiply( vec, scalar, ret );
    return ret;
}

Vector3 Vector3::Negate( const Vector3& vec )
{
    Vector3 ret;
    Negate( vec, ret );
    return ret;
}

Vector3 Vector3::Normalize( const Vector3& vec )
{
    Vector3 ret;
    Normalize( vec, ret );
    return ret;
}

Vector3 Vector3::Reflect( const Vector3& vec, const Vector3& normal )
{
    Vector3 ret;
    Reflect( vec, normal, ret );
    return ret;
}

Vector3 Vector3::Subtract( const Vector3& vec1, const Vector3& vec2 )
{
    Vector3 ret;
    Subtract( vec1, vec2, ret );
    return ret;
}

void Vector3::Add( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    result.X = vec1.X + vec2.X;
    result.Y = vec1.Y + vec2.Y;
    result.Y = vec1.Z + vec2.Z;
}

void Vector3::Clamp( const Vector3& vec, const Vector3& min, const Vector3& max, Vector3& result )
{
    result.X = ( max.X < vec.X ) ? max.X : ( min.X > vec.X ) ? min.X : vec.X;
    result.Y = ( max.Y < vec.Y ) ? max.Y : ( min.Y > vec.Y ) ? min.Y : vec.Y;
    result.Z = ( max.Z < vec.Z ) ? max.Z : ( min.Z > vec.Z ) ? min.Z : vec.Z;
}

void Vector3::Cross( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    Vector3 tmp;

    tmp.X = ( vec1.Y * vec2.Z ) - ( vec1.Z * vec2.Y );
    tmp.Y = ( vec1.Z * vec2.X ) - ( vec1.X * vec2.Z );
    tmp.Z = ( vec1.X * vec2.Y ) - ( vec1.Y * vec2.X );

    memcpy( &result, &tmp, sizeof( Vector3 ) );
}

void Vector3::Distance( const Vector3& vec1, const Vector3& vec2, float32& result )
{
    DistanceSquared( vec1, vec2, result );
    result = sqrt( result );
}

void Vector3::DistanceSquared( const Vector3& vec1, const Vector3& vec2, float32& result )
{
    float32 dx = vec1.X - vec2.X;
    float32 dy = vec1.Y - vec2.Y;
    float32 dz = vec1.Z - vec2.Z;
    result = ( dx * dx ) + ( dy * dy ) + ( dz * dz );
}

void Vector3::Divide( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    result.X = vec1.X / vec2.X;
    result.Y = vec1.Y / vec2.Y;
    result.Z = vec1.Z / vec2.Z;
}

void Vector3::Divide( const Vector3& vec, float32 divider, Vector3& result )
{
    result.X = vec.X / divider;
    result.Y = vec.Y / divider;
    result.Z = vec.Z / divider;
}

void Vector3::Dot( const Vector3& vec1, const Vector3& vec2, float32& result )
{
    result = ( vec1.X * vec2.X ) + ( vec1.Y * vec2.Y ) + ( vec1.Z * vec2.Z );
}

void Vector3::Max( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    result.X = ( vec1.X > vec2.X ) ? vec1.X : vec2.X;
    result.Y = ( vec1.Y > vec2.Y ) ? vec1.Y : vec2.Y;
    result.Z = ( vec1.Z > vec2.Z ) ? vec1.Z : vec2.Z;
}

void Vector3::Min( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    result.X = ( vec1.X < vec2.X ) ? vec1.X : vec2.X;
    result.Y = ( vec1.Y < vec2.Y ) ? vec1.Y : vec2.Y;
    result.Z = ( vec1.Z < vec2.Z ) ? vec1.Z : vec2.Z;
}

void Vector3::Multiply( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    result.X = vec1.X * vec2.X;
    result.Y = vec1.Y * vec2.Y;
    result.Z = vec1.Z * vec2.Z;
}

void Vector3::Multiply( const Vector3& vec, float32 scalar, Vector3& result )
{
    result.X = vec.X * scalar;
    result.Y = vec.Y * scalar;
    result.Z = vec.Z * scalar;
}

void Vector3::Negate( const Vector3& vec, Vector3& result )
{
    result.X = -vec.X;
    result.Y = -vec.Y;
    result.Z = -vec.Z;
}

void Vector3::Normalize( const Vector3& vec, Vector3& result )
{
    float32 length = vec.Length();
    result.X = vec.X / length;
    result.Y = vec.Y / length;
    result.Z = vec.Z / length;
}

void Vector3::Reflect( const Vector3& vec, const Vector3& normal, Vector3& result )
{
    //TODO
}

void Vector3::Subtract( const Vector3& vec1, const Vector3& vec2, Vector3& result )
{
    result.X = vec1.X - vec2.X;
    result.Y = vec1.Y - vec2.Y;
    result.Z = vec1.Z - vec2.Z;
}

float32 Vector3::Length( void ) const
{
    return sqrt( LengthSquared() );
}

float32 Vector3::LengthSquared( void ) const
{
    return ( X * X ) + ( Y * Y ) + ( Z * Z );
}

void Vector3::Normalize( void )
{
    Normalize( *this, *this );
}
